package com.example.mq_sm.mqserver.core;

import com.example.mq_sm.common.MQException;

//
public class Router {
    public boolean checkBindingKey(String bindingKey){
        // direct / fanout 交换机时用不上
        if (bindingKey.length() == 0){
            return true;
        }
        //System.out.println(0);
        for ( int i=0;i<bindingKey.length();i++ ){
            char ch = bindingKey.charAt(i);
            System.out.println(ch);
            if (ch >= '0' && ch <= '9'){
                continue;
            }
            if (ch >= 'a' && ch <= 'z'){
                continue;
            }
            if (ch >= 'A' && ch <= 'Z'){
                continue;
            }
            if (ch == '.' || ch == '_' || ch == '*' || ch == '#'){
                continue;
            }
            return false;
        }

        //System.out.println(1);
        // 检查 * 或者 # 是否是独立的部分
        // aaa.*.bbb 合法；aaa.c*.bbb不合法
        String[] words = bindingKey.split("\\.");
        for (String word : words){
            if (word.length() > 1 && (word.contains(".") || word.contains("#"))){
                return false;
            }
        }
        //System.out.println(2);

        // 约定一个邻里关系是否合法（自己约定的提高效率，非rabbitMQ）
        // *.# #.* #.# 非法；*.* 合法
        for ( int i=0;i<words.length - 1;i++ ){
            if (words[i].equals("#") && words[i].equals("#")){
                return false;
            }
            if (words[i].equals(".") && words[i].equals("#")){
                return false;
            }
            if (words[i].equals("#") && words[i].equals(".")){
                return false;
            }
        }
        //System.out.println(3);
        return true;
    }

    // routingKey 构造规则：
    // 1. 数字，字母，下划线
    // 2. 使用 . 分隔成若干部分
    public boolean checkRoutingKey(String routingKey){
        // fanout 交换机的时候用不上
        if (routingKey.length() == 0){
            return true;
        }
        for ( int i=0;i<routingKey.length();i++ ){
            char ch = routingKey.charAt(i);
            if (ch >= '0' && ch <= '9'){
                continue;
            }
            if (ch >= 'a' && ch <= 'z'){
                continue;
            }
            if (ch >= 'A' && ch <= 'Z'){
                continue;
            }
            if (ch == '.' || ch == '_'){
                continue;
            }
            return false;
        }
        return true;
    }

    // 这个方法用来判定该消息是否可以转发给这个绑定对应的队列
    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws MQException {
        // TODO
        if (exchangeType == ExchangeType.FANOUT){
            // 这个交换机是可以转发给绑定的全部的队列
            return true;
        }else if(exchangeType == ExchangeType.TOPIC){
            // TODO 一个匹配方法
            return routeTopic(binding, message);
        }else {
            throw new MQException("");
        }
    }

    private boolean routeTopic(Binding binding, Message message){
        // 先将这两个 key 进行划分
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");

        int bindingIndex = 0;
        int routingIndex = 0;
        while (bindingIndex < bindingTokens.length && routingIndex < routingTokens.length){
            if (bindingTokens[bindingIndex].equals("*")){
                // 如果遇到 * 直接进入下一轮
                bindingIndex++;
                routingIndex++;
                continue;
            }else if (bindingTokens[bindingIndex].equals("#")){
                // 如果遇到 # ，需要看一下下一个位置，如果没有则匹配成功
                bindingIndex++;
                if (bindingIndex == bindingTokens.length){
                    return true;
                }
                // # 后面还有东西，拿着这个内容去 routingKey 中往后找找到对应的位置
                // findNextMatch 这个方法用来查找该部分在 routingKey 的位置
                routingIndex = findNextMatch(routingTokens, routingIndex, bindingTokens[bindingIndex]);
                if (routingIndex == -1){
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }else {
                // 如果遇到普通字符串，要求两边的内容是一样你的
                if (!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])){
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }

        // 判断是否是双方同时到达末尾
        if (bindingIndex == bindingTokens.length && routingIndex == routingTokens.length){
            return true;
        }
        return false;
    }

    private int findNextMatch(String[] routingTokens, int routingIndex, String bindingToken) {
        for (int i = routingIndex; i < routingTokens.length; i++) {
            if (routingTokens[i].equals(bindingToken)) {
                return i;
            }
        }
        return -1;
    }

}
